

/**===================
 * 变量的声明
 * DOM缓存
 * ===================*/

// 获取 html 元素
var html = document.documentElement;
var table = document.getElementsByClassName('gameTable')[0];
// 选项卡
var selectModel = document.getElementsByClassName('selectModel')[0];
var gameOver = document.getElementsByClassName('gameOver')[0];
var restart = document.getElementsByClassName('restart')[0];
var easy = document.getElementById('easy');
var time = document.getElementById('time');
var mine = document.getElementById('mine');
var tbody = table.firstElementChild.firstElementChild;
//用户是否出错
var flag = true;




/**==========================
 * 三个主要对象的构造函数
 * ==========================*/

/**创建棋盘对象
 *
 * 其中包含一些方法：
 * 初始化棋盘方法：4行3列的表格
 * 新增一行方法（按键位置随机，）
 * 向下移动的动画方法
 */
function Layout(){
    /**
     * start和restart时调用，用于初始化棋盘
     * 首先将棋盘全置为白色
     * 然后随机出一个数将其置为黑块
     */
    this.init = function (){
        // 遍历出每个 tr
        for (var i=0; i<4; i++){
            // 将每个 td 都设置为默认色
            for (var j=0; j<3; j++){
                table.firstElementChild.firstElementChild.children[i].children[j].style.backgroundColor = '';
            }
            // 每行随机出一个黑块
            var num = Math.round(Math.random() * 2);
            var style = table.firstElementChild.firstElementChild.children[i].children[num].style;
            style.backgroundColor = '#333'
        }
    }

    /**
     * 消除最后一行（第4行）
     * 最上方添加一行
     *
     * 该方法为原型方法和 isTrue 方法一起在 game 对象中的交互方法中实现
     *
     * 涉及到的知识点： 需要用到 DOM 中删除最后一个节点和增加新节点：
     * Element对象用于查找元素： firstElementChild（第一个子元素），lastElementChild（最后一个子元素）
     * Node 对象用于删除增加元素： removeChild()（删除节点），insertBefore()（指定节点之前插入节点）
     */
    this.move = function(){
            var firstLine = table.firstElementChild.firstElementChild.children[0];
            var forthLine = table.firstElementChild.firstElementChild.children[3];

            // 删除最后一行
            tbody.removeChild(forthLine);

            // 新建tr节点
            var newTr = document.createElement('tr');
            // 为 tr 新增 td
            var newTd1 = document.createElement('td');
            var newTd2 = document.createElement('td');
            var newTd3 = document.createElement('td');

            // 为新增的 newTr 添加td
            newTr.appendChild(newTd1);
            newTr.appendChild(newTd2);
            newTr.appendChild(newTd3);

            // 为 td 随机生成黑块
            var randomNewTd = newTr.children[Math.round(Math.random() * 2)]
            // 设置style
            randomNewTd.style.background = '#333';
            //添加到tbody
            tbody.insertBefore(newTr, firstLine);
        }
}


/**创建键盘对象
 *
 * 其中包含一些方法：
 * 键盘敲击事件绑定的方法
 * 判断是否敲击正确的方法
 */
function Board(){
    /**
     * 判断用户是否按正确
     * 该方法为原型
     * 和 move 一起在 game 的交互方法中实现
     *
     * if 该方法返回true 则调用 move方法
     *
     * @param value 用户键盘按下的值
     * @param index 黑块在最后一行的位置
     * @returns {boolean} 用户点击正确返回 true
     */
    this.isTrue = function (value, index){
        return value === 'j' && index === 1 || value === 'k' && index === 2 || value === 'l' && index === 3;
    }

    /**
     * 为传入的 DOM 节点绑定键盘事件
     *
     * 此项目中用来为 html 全局绑定键盘的敲击事件
     *
     * @param element
     */
    this.bind = function (element){
        element.addEventListener('keypress', keypress);
    }

}
// Board 的原型指向 Layout
Board.prototype = new Layout();


/**创建游戏对象
 *
 * 其中包含一些方法：
 * 初始化游戏方法（继承 layout）
 * 游戏交互逻辑方法（继承keyDown的两个方法：move移动，isTrue按键是否正确）在这个对象中将两个方法做了合并
 * 结束游戏逻辑方法
 * 重新开始游戏方法（继承layout）
 */
function Game(){
    // 开始游戏
    this.startGame = function(){
        // 初始化
        this.init();
        // 隐藏模式选择界面
        selectModel.style.display = 'none';

        // 开始计时
        var seconds = document.getElementsByClassName('seconds')[0];
        // 计时器中的秒数
        var num = 0;
        // 一毫秒刷新一次计时器
        var t = setInterval(function () {
            num += 0.01;
            // 显示两位小数
            seconds.textContent = num.toFixed(2)+'秒';
        }, 10);

    }

    // 结束游戏
    this.over = function (){
        // 用户点击失败
        if (!flag){
            // 解绑事件
            html.removeEventListener('keypress',keypress)
            // 显示游戏失败界面
            gameOver.style.display = 'block';
            restart.style.display = 'block';

            // 清除计时器
            clearInterval(t);
        }
    }

    // 重新开始
    this.restart = function (){
            selectModel.style.display = 'block';
            gameOver.style.display = 'none';

            flag = true;
    };
}
// 继承
Game.prototype = new Board();





/**===================
 * 一些全局函数
 * ===================*/

// 判断最后一行哪个块为黑
function isBlock(){
    // 检测最后一行中为黑色块的索引位置
    for (var i=0; i<3; i++){
        // 获取 style （有待优化，for循环损耗性能，并且每次都需要查询DOM树）
        var style = table.firstElementChild.firstElementChild.children[3].children[i].style;
        //若其中 backgroundColor 不为 '' 则返回它的索引位置 +1
        if (style.backgroundColor !== ''){
            return i+1;
        }
    }
}
// 绑定在键盘上的敲击事件，放在外边方便解绑
function keypress(event){
    // 若按键正确则进行后序操作
    if (isTrue(event.key, isBlock())){
        move(true);
    }else{
        flag = false;
    }
}

var g = new Game();
console.log(g.init)


easy.addEventListener('click', function (){
    // 点击普通模式之后显示游戏页面
    selectModel.style.display = 'none';

    // 为 html 绑定键盘事件
    this.bind(html);

    // 获取计时器元素
    var seconds = document.getElementsByClassName('seconds')[0];
    // 计时器中的秒数
    var num = 0;
    // 一毫秒刷新一次计时器
    var t = setInterval(function () {
        // 用户游戏失败了
        if (!flag){
            // 解绑键盘事件
            html.removeEventListener('keypress',keypress)
            // 显示游戏失败界面
            gameOver.style.display = 'block';
            restart.style.display = 'block';

            // 清除计时器
            clearInterval(t);
        }
        num += 0.01;
        // 显示两位小数
        seconds.textContent = num.toFixed(2)+'秒';
    }, 10);
});